package cn.autumnorange.app.common.repository.util;

import cn.autumnorange.app.common.util.DateConverUtil;
import cn.autumnorange.app.common.util.Reflector;
import cn.autumnorange.app.common.util.StringUtils;

import javax.persistence.Table;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.util.*;

/**
 * @author wsf
 */
public class EntityUtil {
    public static final String SET_METHOD = "set";

    public static final String GET_METHOD = "get";

    /**
     * 过滤属性不设值
     */
    public static final List<String> FILTER_FIELD =
            Arrays.asList("id", "createId", "createTime", "updateId", "updateTime");

    /**
     * 获取Hql表名
     */
    public static String getHqlTableName(Class clazz) {
        return clazz.getSimpleName();
    }

    /**
     * 获取Sql表名
     */
    public static String getSqlTableName(Class clazz) {
        Table annotation = (Table) clazz.getAnnotation(Table.class);
        return annotation.name();
    }

    public static void putMapDataIntoEntity(Map<String, Object> map, Object entity) {
        try {
            if (entity != null && map != null && map.size() > 0) {
                // 获取传入实体类的属性Filed数组
                // Field[] field_arr =
                // Class.forName(entity.getClass().getCanonicalName()).getDeclaredFields();
                Set<Field> field_arr = Reflector.getAllDeclaredFields(entity.getClass());
                // 遍历数组
                for (Field field : field_arr) {
                    // 获取属性名称
                    String fieldName = field.getName();
                    // 判断map中是否存在对应的属性名称（注：这个方法要想使用就必须保证map中的key与实体类的属性名称一致）
                    if (!FILTER_FIELD.contains(fieldName) && map.containsKey(fieldName)) {
                        // 获取属性的类型 字符串String fieldType = field.getGenericType().toString();
                        final Class<?> fieldTypeClz = field.getType();
                        // 调用本类中的帮助方法来获取当前属性名对应的方法名（“set”为getMethodName方法的第二个参数）
                        String methodName = getMethodName(fieldName, SET_METHOD);
                        // 获取当前key对应的值
                        Object fieldValue = map.get(fieldName);
                        // 根据获取的方法名称及当前field的类型获取method对象
                        Method method = getDeclaredMethod(entity, methodName, fieldTypeClz);
                        // 根据属性类型转换值类型
                        fieldValue = setFieldValue(fieldValue, fieldTypeClz);
                        // 调用当前实体类的方法将数值set进去
                        method.invoke(entity, fieldValue);
                    }
                }
            }
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    /**
     * 循环向上转型, 获 * @param object : 子类对象
     *
     * @param methodName     : 父类中的方法名
     * @param parameterTypes : 父类中的方法参数类型
     * @return 子类或父类中的方法对象
     */
    public static Method getDeclaredMethod(
            Object object, String methodName, Class<?>... parameterTypes) {
        Method method = null;
        for (Class<?> clazz = object.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
            try {
                method = clazz.getDeclaredMethod(methodName, parameterTypes);
                return method;
            } catch (Exception e) {
                // 这里甚么都不能抛出去。
                // 如果这里的异常打印或者往外抛，则就不会进入
            }
        }
        return null;
    }

    /**
     * @param fieldName  属性名
     * @param methodType 获取方法类型（set or get）
     * @return 方法名称，反射使用
     * @author eiven
     */
    public static String getMethodName(String fieldName, String methodType) {
        String methodName = "";
        if (StringUtils.isNotBlank(fieldName)) {
            methodName = StringUtils.toUpperCaseForIndex(fieldName);
        }
        return methodType + methodName;
    }

    /**
     * 根据属性类型转换值类型
     */
    public static Object setFieldValue(Object fieldValue, Class<?> fieldTypeClz) {
        Object newValue = null;
        if (fieldValue == null) {
            return newValue;
        }
        if (fieldTypeClz.isAssignableFrom(String.class)) {
            newValue = fieldValue.toString();
        } else if (fieldTypeClz.isAssignableFrom(Integer.class)) {
            newValue = Integer.valueOf(fieldValue.toString());
        } else if (fieldTypeClz.isAssignableFrom(Double.class)) {
            newValue = Double.valueOf(fieldValue.toString());
        } else if (fieldTypeClz.isAssignableFrom(Date.class)) {
            newValue = DateConverUtil.getDatebyStr(fieldValue.toString());
        } else if (fieldTypeClz.isAssignableFrom(Timestamp.class)) {
            newValue = Timestamp.valueOf(fieldValue.toString());
        } else if (fieldTypeClz.isAssignableFrom(BigInteger.class)) {
            newValue = new BigInteger(fieldValue.toString());
        } else if (fieldTypeClz.isAssignableFrom(BigDecimal.class)) {
            newValue = new BigDecimal(fieldValue.toString());
        } else if (fieldTypeClz.isAssignableFrom(Boolean.class)) {
            if ("是".equals(fieldValue.toString())) {
                newValue = Boolean.TRUE;
            } else if ("否".equals(fieldValue.toString())) {
                newValue = Boolean.FALSE;
            } else {
                newValue = Boolean.parseBoolean(fieldValue.toString());
            }
        }
        return newValue;
    }
}
